package com.hxk.juc;

import java.util.concurrent.TimeUnit;

/**
 * 手写一个死锁案例
 * 怎么样才能达到死锁？
 *      在两个或两个以上的线程中，线程A持有自己的锁，还想获取线程B的锁，线程B持有自己的锁，还想获取线程A的锁，这样就会出现死锁，一句话【吃着碗里的看着锅里的】
 * 怎么排查线程死锁？
 *      第一步：使用java的命令 jps -p 获取线程编号
 *      第二步: 在通过java的命令 jstack 上一步得到的线程编号
 *   排查结果：
 *      "Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000000002e9c800 nid=0x3bd4 in Object.wait() [0x0000000018cff000]
         java.lang.Thread.State: WAITING (on object monitor)
         at java.lang.Object.wait(Native Method)
         - waiting on <0x00000000d6008ed0> (a java.lang.ref.ReferenceQueue$Lock) 【注意这一行】
         at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
         - locked <0x00000000d6008ed0> (a java.lang.ref.ReferenceQueue$Lock) 【注意这一行】
         at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
         at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:212)

         "Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000017959000 nid=0x29e0 in Object.wait() [0x0000000018bff000]
         java.lang.Thread.State: WAITING (on object monitor)
         at java.lang.Object.wait(Native Method)
         - waiting on <0x00000000d6006bf8> (a java.lang.ref.Reference$Lock) 【注意这一行】
         at java.lang.Object.wait(Object.java:502)
         at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
         - locked <0x00000000d6006bf8> (a java.lang.ref.Reference$Lock) 【注意这一行】
         at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

         "VM Thread" os_prio=2 tid=0x0000000017958000 nid=0x38f0 runnable

 */
public class DeadLockCase {

    public static void main(String[] args) {
        String lockA = "lockA";
        String lockB = "lockB";
        new Thread(new MyRunnable(lockA,lockB),"A").start();
        new Thread(new MyRunnable(lockB,lockA),"B").start();
    }
}

class MyRunnable implements Runnable{

    //自己的锁
    private String selfLock;

    //别人的锁
    private String otherLock;

    public MyRunnable(String selfLock, String otherLock) {
        this.selfLock = selfLock;
        this.otherLock = otherLock;
    }

    @Override
    public void run() {
        //持有自己的锁
        synchronized (selfLock){

            System.out.println(Thread.currentThread().getName()+"持有自己的锁："+selfLock);
            try {
                TimeUnit.MINUTES.sleep(300);//如果这里不等待，可能不会出现死锁情况
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (otherLock){

                System.out.println(Thread.currentThread().getName()+"获取别人的锁："+otherLock);
            }
        }
    }
}